import { createDOM } from './react_dom'

export let updateQueue = {
  isBatchingUpdate: false,
  updaters: new Set(),
  batchUpdate() {
    for (let updater of updateQueue.updaters) {
      updater.updateClassComponents()
    }
    //开启批量更新
    this.isBatchingUpdate = false
  },
}

class update {
  constructor(classInstance) {
    this.classInstance = classInstance
    this.pendingStates = []
    this.callbacks = []
  }
  addState(partialState, callback) {
    this.pendingStates.push(partialState)
    if (typeof callback == 'function') this.callbacks.push(callback)
    this.emitUpdate()
    if (updateQueue.isBatchingUpdate) {
      //判断是否批量更新
      updateQueue.updaters.add(this)
    } else {
      this.updateClassComponents() //直接更新组件函数
    }
  }
  updateClassComponents() {
    const { classInstance, pendingStates, callbacks } = this
    if (pendingStates.length > 0) {
      // classInstance.state = this.getSate() //计算新状态
      // classInstance.forceUpdate()
      // callbacks.forEach((cb) => cb())
      // callbacks.length = 0 //回调清空
      shouldUpdate(classInstance, this.getSate())
    }
  }
  getSate() {
    const { classInstance, pendingStates } = this
    const { state } = classInstance
    pendingStates.forEach((nextSate) => {
      if (typeof nextSate == 'function') {
        nextSate = nextSate.call(classInstance, state)
      }
      state = { ...state, ...nextSate }
    })
    pendingStates.length = 0
    return state
  }
  forceUpdate() {
    this.componentWillUpdate && this.componentWillUpdate()
    const newRenderDom = this.render()
    // updateClassComponents(this, newValue)
    const oldRenderVdom = this.oldRenderVdom
    const oldDom = oldRenderVdom.dom

    const currenRenderVdom = compareTwoVdom(
      this.oldRendervdom.dom.parentNode,
      this.oldRendervdom,
      newRenderDom
    ) //对比函数 对比新的虚拟节点和老的虚拟节点
    this.oldRenderVdom = currenRenderVdom
    this.componentDieUpdate && this.componentDieUpdate()
  }
  emitUpdate(newProps) {
    if (updateQueue.isBatchingUpdate) {
      updateQueue.updaters.add(this)
    } else {
      this.updateClassComponents()
    }
  }
}

class Component {
  static isReactComponent = true
  constructor(props) {
    this.props = props
    this.state = {}
    this.Updater = new update(this)
  }
  setState(partialState, cb) {
    this.updater.addState(partialState, cb)
    // let state = this.state
    // this.state = { ...state, ...partialState }
    // // 调用子类的方法
    // let newVdom = this.render()
    // updateClassComponents(this, newVdom)
  }
  render() {
    throw new Error('此类需要子类实现')
  }
}
//更新类组件
// function updateClassComponents(classInstance, newVdom) {
//   let lodDOM = classInstance.dom
//   let newDOM = createDOM(newVdom)
//   lodDOM.parentNode.replaceChild(newDOM, lodDOM)
//   classInstance.dom = newDOM
// }

/**
 * 判断组件是否需要更新
 * @param {*} classInstance 当前组件实例
 * @param {*} nextState 最新状态值
 */
function shouldUpdate(classInstance, nextState) {
  classInstance.state = nextState
  if (
    classInstance.shouldUpdateComponentUpdate &&
    !classInstance.shouldUpdateComponentUpdate(
      classInstance.props,
      classInstance.state
    )
  ) {
    return
  }
}

/**
 *对当前组件dom-dif比较
 * @param {*} parenDOM 父节点
 * @param {*} oldVdom 上一次的虚拟dom
 * @param {*} newVdom 这一次的新的虚拟dom
 */
export function compareTwoVdom(parenDOM, oldVdom, newVdom, nextDom) {
  //老的虚拟dom和新的虚拟dom都是null
  if (!oldVdom && !newVdom) {
    return null
    //如果老的虚拟dom有 新的虚拟dom没有
  } else if (oldVdom && !newVdom) {
    const currentDOM = findDOM(oldVdom)
    currentDOM && parenDOM.removeChild(currentDOM) //删除节点
  } else if (!oldVdom && newVdom) {
    const newDom = createDOM(newVdom)
    nextDom
      ? parenDOM.insertBefore(newDom, nextDom)
      : parenDOM.appendChild(newDom)
    parenDOM.appendChild(newDom) //添加节点
    return newVdom
  } else if (oldDom && newVdom && oldVdom.type !== newVdom.type) {
    const oldDOm = findDOM(oldVdom) //老的dom
    const newDom = createDOM(newVdom) //新的dom
  }
}
/**
 *查找此虚拟dom对应的真实dom
 * @param {*} vdom
 */
function findDOM(vdom) {
  const { type } = vdom
  let dom
  if (typeof type == 'function') {
    if (type.isReactComponent) {
      dom = findDOM(vdom.classInstance.oldRenderVdom)
    } else {
      dom = findDOM(vdom.oldRenderVdom)
    }
  } else {
    dom = vdom.dom
  }
  return dom
}

export default Component
